#!/usr/local/bin/python2.7
# encoding: utf-8
'''
NervuresDesignTool -- Outil de conception/simulation de parapentes Nervures
Classe xxx
Description :
@module : graphics
@author:      puiseux
@copyright:   2013 Nervures. All rights reserved.      
@license:    LGPL
@contact:    be@nervures.com, pierre@puiseux.name
@deffield    creation: 19 janv. 2013
'''
import sys
from utilitaires.utilitaires import whoami, debog, trace, baryCentre
from PyQt4 import QtCore, QtGui
from PyQt4.Qt import SIGNAL
# from preferences import NodePrefs, ParticularNodePrefs, AncrageNodePrefs
import graphics.preferences as preferences
from common import p2t, p2s
import numpy as np

# class Noeud(QtGui.QGraphicsRectItem):
class Noeud(QtGui.QGraphicsObject):
    """
    Fonctionnalités il y en a essentiellement 2 :
    - paint, mettre les attributs qui conviennent pour le tracé
    - itemChange : méthode hyper sensible, appelle le updateNode(self) de son parentItem en cas de self.ItemPositionHasChanged
    """
    prefs = preferences.NodePrefs
    Type = QtGui.QGraphicsItem.UserType + 1
    def __init__(self, point=None, parent=None, role=u"noeud"):
        """
        Parametres :
        ----------
        - point = les coord
        - parent :  un QGraphicsItem
        """
        super(Noeud, self).__init__(parent)
        self.role = role
#         self.setRect(self.prefs.RECTF)
        self.setCursor(QtCore.Qt.CrossCursor)
        self.setAcceptHoverEvents(True)
#        self.graph = weakref.ref(NGraphicsUi)
#         self.setFlag(QtGui.QGraphicsItem.ItemStacksBehindParent)
        self.setCacheMode(self.DeviceCoordinateCache)
        self.setZValue(1)
        if point is not None :
            if isinstance(point, QtCore.QPointF) : 
                self.setPos(point)
            elif len(point)>0 : 
                point = np.asarray(point)
                point.shape = (2,)
                self.setPos(point[0], point[1])
#         self.showNumber()
        self.angle = 0.0
        self.shearx = self.sheary = 0.0
        self.homx = self.homy = 1.0
        self.createActions()
    
    def boundingRect(self):
        return self.prefs.RECTF 
    
    def createActions(self):
        self.actionSetRoleBase = QtGui.QAction(u"Définir le noeud de base", self.scene())
        self.actionSetRoleBase.setCheckable(True)
        QtCore.QObject.connect(self.actionSetRoleBase, SIGNAL("triggered(bool)"), self._switchRole)
        self.actions = [self.actionSetRoleBase]

    def _switchRole(self, role):
        '''
        Switch, connecté aux actionSetRoleBase, ...
        C'est le parentItem (i.e. un EGraphicsProfilItem) qui décide des actions à entreprendre.
        '''
        sender = self.sender()
        if sender in (self.actionSetRoleBase, ) :
            self.parentItem().setBaseNode(self)
#             self.role = 'base'
        else : 
            pass
            
    def _setRole(self, role):
        self._role = role
        self.setFlag(QtGui.QGraphicsItem.ItemIgnoresTransformations, True)#taille fixe
        if role in ('base',) :
            self.actionSetRoleBase.setChecked(True)
            self.actionSetRoleBase.setText(u'Noeud de base')
            self.prefs = preferences.ReperePrefs
            self.setFlag(QtGui.QGraphicsItem.ItemSendsGeometryChanges, True)
            self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
            self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, False)
            self.setFlag(QtGui.QGraphicsItem.ItemStacksBehindParent, True)
            #On cache le noeud derrière le profil pour accrocher le profil lorsque l'on tente de le selectionner.
        elif role in ('repere', ) :
            self.prefs = preferences.ReperePrefs
            self.setFlag(QtGui.QGraphicsItem.ItemSendsGeometryChanges, True)
            self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
            self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
        elif role in ('fantome',) : #beaucoup de noeuds =>  la même instance : la classe elle-même, partagée par tous les noeuds.
            self.prefs = preferences.PhantomNodePrefs
            self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, False)
            self.setFlag(QtGui.QGraphicsItem.ItemSendsGeometryChanges, False)
            self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
            self.setFlag(QtGui.QGraphicsItem.ItemStacksBehindParent, False)
            
            self.setSelected(False)
        else : 
            self.prefs = preferences.NodePrefs
            self.setFlag(QtGui.QGraphicsItem.ItemSendsGeometryChanges, True)
            self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
            self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
        self.update()
        
    def _getRole(self):
        return self._role
    role = property(_getRole, _setRole)

        
    def __len__(self):
        return 1
    def __str__(self):
        return ' ; '.join(self.info)
    
    def _getInfo(self):
        return  [u"<%s>"%type(self).__name__, u"rôle=%s"%self.role, u"Numéro=%d"%self.number]#,u"sceneCoord=%s"%p2s(self.scenePos())]
    info = property(_getInfo)

    def __call__(self, i):
        x, y = p2t(self.scenePos())
#         if i==-1 : return x, y
        if i == 0 : return x
        elif i == 1 : return y
    
    def __getitem__(self, k):
        return self.__call__(k)
        
    def type(self):
        return self.Type
    
    def attach(self, node):
        '''le noeud self est attaché à node, pour BF profil ou polygone par exemple'''
        self.setParentItem(node)
    
    def scale(self, *args):
        trace(self, u"pas de mise à l'échelle")
        return
    
    def moveNode(self, arg):
        """
        ne sert à rien, juste a éviter un message d'alerte
        """
#        print whoami(self)
        pass
    
    def updateTransform(self):
        centre = baryCentre(self.points).flatten()
        centre = QtCore.QPointF(*centre)
        centre = self.mapFromScene(centre)
        trace(self, 'centre, self.shearx, self.sheary, self.angle', centre, self.shearx, self.sheary, self.angle)
        transform = QtGui.QTransform()
        transform.shear(self.shearx, self.sheary)
        transform.scale(self.homx, self.homy)
        transform.rotate(self.angle)
        self.setTransformOriginPoint(QtCore.QPointF(centre))
#         self.setTransformOriginPoint(QtCore.QPointF(0,0))
        self.setTransform(transform)
    def rotate(self):
        pass
    
    def itemChange(self, change, value):
        """
        ATTENTION, ne surtout pas oublier le RETURN dans 
        return super(Noeud, self).itemChange(change, value)
        """
        if change == QtGui.QGraphicsItem.ItemPositionHasChanged:
#            trace(self, 'id(self) = %d'%id(self), type(self).__name__)
#            print trace(self), 'ItemPositionHasChanged',
#            self.update()
            try : 
                self.parentItem().moveNode(self)
            except AttributeError as msg: 
#                print>>sys.stderr, whoami(self), str(msg) + ' : pas de parent'
                pass
#            print
        return super(Noeud, self).itemChange(change, value)
     
    def hoverEnterEvent(self, event):
        self.setToolTip(self.__str__())
    
    def mouseReleaseEvent(self, event):
#         trace(self)
        try : self.parentItem().update()
        except AttributeError as msg : 
            trace(self, msg)
        self.update()
        super(Noeud,self).mouseReleaseEvent(event)
    
    def showNumber(self):
        numbertext = QtGui.QGraphicsSimpleTextItem(str(self.number), self)
        self.numbertext = numbertext
        numbertext.show()
        
    def hideNumber(self):
        try : self.numbertext.hide()
        except AttributeError : 
            pass
        
    def paint(self, painter, option, widget):
#        print painter, option
        if self.isSelected() : 
            shape = self.prefs.SELECTED_SHAPE
            pen = self.prefs.SELECTED_PEN
            brush = self.prefs.SELECTED_BRUSH
        else : 
            shape = self.prefs.SHAPE
            pen = self.prefs.PEN
            brush = self.prefs.BRUSH
            
        painter.setPen(pen)
        painter.setBrush(brush)
#         shape(painter, self.boundingRect())
        shape(painter, self.prefs.RECTF)
#        painter.setPen(QtCore.Qt.DotLine)
#         painter.drawRect(self.self.prefs.RECTF)
#         super(Noeud, self).paint(painter, option, widget)
    
    def _getNumber(self):
        try : 
            return self.parentItem().nodes.index(self)
        except AttributeError :
            # le parent n'a pas d'attribut nodes, on essaye le grand-pere
            try : 
                # utile lorsqu'un polyline est fermé, le parent du dernier noeud est le noeud 0.
                # Dans ce cas c'est le grand-pere qui a l'attribut nodes (=liste des noeuds).
                return self.parentItem().parentItem().nodes.index(self)
            except AttributeError :
                return -1
        except ValueError :#Un ancrage n'est pas dans la liste parent.nodes
            return -1
        
    def _getWidth(self):return self.boundingRect().width()
    def _getHeight(self):return self.boundingRect().height()
    def _getPoints(self):return np.asarray([[self.pos().x(), self.pos().y()],])
    dx = width  =  property(_getWidth, doc=u"Largeur")
    dy = height =  property(_getHeight, doc=u"Hauteur")
    number = property(_getNumber, doc=u"numero du point dans le polygone, ou -1 s'il n'a pas de parent")
    points = property(_getPoints, doc=u"Pour cloisons, ne pas supprimer")
    
    
        
if __name__ == "__main__":
    pass